home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / GNUUCP_2 / SOURCE / GNUUCP.C < prev    next >
Text File  |  1990-07-16  |  39KB  |  1,484 lines

  1. /*
  2.  * @(#)gnuucp.c 1.29 87/09/29    Copyright 1987 Free Software Foundation, Inc.
  3.  *
  4.  * Copying and use of this program are controlled by the terms of the
  5.  * GNU Emacs General Public License.
  6.  *
  7.  * Derived from:
  8.  * i[$]uuslave.c    1.7 08/12/85 14:04:20
  9.  * which came from the ACGNJ BBS system at +1 201 753 9758.  Original
  10.  * author unknown.  Many people, too numerous to list here, have contributed
  11.  * changes and ports to this program.
  12.  */
  13.  
  14. char version[] = "Version Fort Pond Research-2.6";
  15. #include <console.h>
  16. #include <SerialDvr.h>
  17. #include <signal.h>
  18. #include <profile.h>
  19. extern int inRefNum;
  20.  
  21. /*
  22.  
  23. This program implements the uucp (Unix-to-Unix CoPy) protocol, used to
  24. transfer mail, files, and Usenet news among Unix machines.  UUCP comes
  25. free with Unix (unless you get a sleazeoid version like Xenix, where
  26. they charge you extra for it), but you don't get sources.  You can buy
  27. a commercial program for MSDOS, called UULINK, which also implements
  28. this protocol.  UULINK costs $300 and you still don't get sources.
  29. This program not only runs on Unix and MSDOS, but on many other
  30. machines, and comes with the Free Software Foundation copyright, which
  31. guarantees you access to sources.
  32.  
  33. The protocol requires a full 8-bit data path with no characters inserted
  34. or deleted (e.g. ^S and ^Q are used as DATA characters).  Simple serial
  35. ports and modems do this; most complicated networks do not, at least without
  36. setting up odd modes and such.  Telenet's PC Pursuit works fine though.
  37.  
  38. The basic flow of the protocol is that the calling machine will send down
  39. a line of text saying what it wants to do (send a file, receive a file,
  40. or hang up).  (The lines of text are encapsulated into packets; see below.)
  41. The called machine responds with a "yes" or "no" answer, and if the answer
  42. was yes, it sends or receives the file.  Files are terminated with a
  43. packet containing 0 bytes of data.  Then the system that received the file
  44. sends a "copy succeeded" or "copy failed" line to the other end, and 
  45. they go back to "what do we do now".  A request to hang up should be
  46. answered "no" if the called machine has some mail or files it wants to
  47. send to the calling machine; the two machines reverse roles and the calling
  48. machine goes into "what do we do now".  If a hangup request is answered "yes",
  49. the call is terminated.
  50.  
  51. The data flow described above is actually sent by a lower level "protocol
  52. module".  The default "g" protocol module sends the data in packets containing
  53. checksums and acknowledgements.  Each packet can either hold a short
  54. control message, e.g. an ack, or a data block.  The data blocks are
  55. numbered with a 3-bit counter, and sent with a checksum.  If the sender
  56. has not received an acknowledgement for a data block within a certain
  57. time, it retransmits the block.  The size of a data block is negotiated
  58. at the start of a call.  To send a block with fewer bytes, a "short
  59. data" block is sent, which is just as big as a "long data" block, but
  60. contains a 1- or 2-byte count of "how many bytes in this block are just
  61. padding".  This is a cute trick since it always works (e.g. if you want
  62. to send 1023 out of 1024 bytes, you only need one byte for the count;
  63. while if you want to send 1 byte out of 1024 then you have enough space
  64. for the count to be 2 bytes).
  65.  
  66. The short control messages are used to start the call and negotiate the
  67. packet size and the "window size", to acknowledge or reject packets,
  68. and to terminate the packet protocol at the end of a call.  The window
  69. size is how many packets one side can send before it will stop and wait
  70. for an acknowledgement from the other side.  A window size of 1 makes
  71. for a half-duplex protocol (which is what gnuucp currently
  72. implements), but also makes it easy to implement on micros that don't
  73. handle serial lines with interrupts.  In window 1, you just keep
  74. sending the same packet until the other side acknowledges it.  Unix
  75. always uses a window size of 3, which is the max that can be dealt with
  76. given the 3-bit packet numbers (for reasons that would take more space
  77. than I want to spend here).  This gives much better throughput, but
  78. requires full duplex serial port handling and more complicated
  79. acknowledgement strategies.
  80.  
  81. In receiving data, the "g" protocol scans for a DLE (hex 10) which
  82. indicates the start of a packet, and the next 5 bytes are read and
  83. checked.  If they pass, this is a good packet and it is acted upon.
  84. (If it's a data packet, we have to read in and check the data part
  85. too.)  If the checks fail, all the bytes read so far should be rescanned
  86. for another DLE, since it's possible that some characters were dropped
  87. and the first DLE we saw was actually part of a data packet.
  88.  
  89. Other protocol modules have been implemented; e.g. the "f" protocol which
  90. eliminates the packets and acknowledgements, for reduced overhead when
  91. running over an error-free, flow controlled connection on an X.25 network.
  92. There has been talk of a "z" protocol which implements ZMODEM.  So far,
  93. none of these modules are supplied with gnuucp, though "f" is public domain
  94. and "z" is intended to be, because they are not ported and tested yet.
  95.  
  96. At the start of a call, the caller sends the list of protocols it supports,
  97. and the callee picks the best one it knows and says "use this one please".
  98.  
  99. At the low level, full 8-bit bytes are sent out and received on an async
  100. serial port.
  101. */
  102.  
  103. #include "includes.h"        /* System include files, system dependent */
  104. #include "uucp.h"        /* Uucp definitions and parameters */
  105.  
  106. #define    MAX_FLAGS    40
  107.  
  108. extern int errno;
  109.  
  110. char    Progname[20];            /* Our program name e.g. "uuq" */
  111. char    ttynam[NAMESIZE],        /* Name of tty we use as serial port */
  112.     srcnam[NAMESIZE],        /* Source file name */
  113.     dstnam[NAMESIZE],        /* Dest file name */
  114.     flags[MAX_FLAGS],        /* Flags from file xfer cmd */
  115.     temp[NAMESIZE];            /* Temp file name */
  116.  
  117. int    fdtty,                /* Opaque handle to pass to protocol */
  118.     ignore_time_restrictions = 0,    /* Call out even if L.sys sez no */
  119.     mode;                /* File mode from file xfer cmd */
  120.  
  121. int   f_wait    = 0;    /* FIXME, unreferenced now */
  122. int   loop    = 1;    /* Loop accepting logins if tty name specified */
  123. int   curtemp = 0;
  124.  
  125. #define    MAX_STRING    200    /* Max length string to send/expect */
  126.  
  127. /* Strings sent by the slave side to the master */
  128. char msgo0[] = "\nlogin: ";
  129. char msgo1[] = "Password:";
  130. char msgo2[] = "\20Shere\0";
  131. char msgo3[] = "\20ROK\0";
  132. char msgo3a[]= "\20Pg\0";
  133. char msgo4[] = "\20OOOOOOO\0";
  134.  
  135. /* Strings sent by the master to the slave */
  136. char msgi0[] = "uucp\n";
  137. char msgi1[] = "s8000\n";
  138. /* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
  139. char msgi3[] = "\20Ug\0";
  140. char msgi4[] = "OOOOOO";
  141.  
  142. /*
  143.  * Protocol switch data structure
  144.  */
  145. struct proto {
  146.     char    p_id;
  147.     int    (*p_turnon)();
  148.     int    (*p_rdmsg)();
  149.     int    (*p_wrmsg)();
  150.     int    (*p_rddata)();
  151.     int    (*p_wrdata)();
  152.     int    (*p_turnoff)();
  153. };
  154.  
  155. extern int gturnon(), grdmsg(), gwrmsg(), grddata(), gwrdata(), gturnoff();
  156. /*
  157.  * This is how the "f" protocol would be declared:
  158.  * extern int fturnon(), frdmsg(), fwrmsg(), frddata(), fwrdata(), fturnoff();
  159.  */
  160.  
  161. struct proto ptbl[] = {
  162.     /* "f" protocol to run on X.25 PADs */
  163.   /*    {'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff}, */
  164.     /* Original "g" protocol for dialup async modem lines */
  165.     {'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff},
  166. };
  167.  
  168. struct proto *curproto = &ptbl[0];
  169.  
  170. #define    turnon    (*curproto->p_turnon)
  171. #define    rdmsg    (*curproto->p_rdmsg)
  172. #define    wrmsg    (*curproto->p_wrmsg)
  173. #define    rddata    (*curproto->p_rddata)
  174. #define    wrdata    (*curproto->p_wrdata)
  175. #define    turnoff    (*curproto->p_turnoff)
  176.  
  177. /*
  178.  * Read from the serial port a null-terminated string.
  179.  * The string FIXME should not overrun MAX_STRING.
  180.  * String starts with first printing character.
  181.  */
  182. int
  183. getstring(where)
  184.     register char *where;
  185. {
  186.     register int data, count = 0;
  187.  
  188.     DEBUG(8, "Getstring:  ", 0);
  189.     /* Read data until null character */
  190.     while ( (long)((data = xgetc()) != (long)EOF)) {
  191.         data &= 0x7F;
  192.         if (DEBUG_LEVEL(8)) {
  193.             printf("%02x%c ", data, isprint(data)? data: ' ');
  194.         }
  195.  
  196.         where[count++] = data;
  197.         if (data == 0x00) {
  198.             if (DEBUG_LEVEL(8)) putchar('\n');
  199.             return SUCCESS;
  200.         }
  201.         if (count == 1 && !isprint(where[0]))
  202.             count = 0;
  203.     }
  204.     if (DEBUG_LEVEL(8)) putchar('\n');
  205.     return FAIL;
  206. }
  207.  
  208.  
  209. /*
  210.  * Medium level input routine.
  211.  *
  212.  * Look for an input string for the send-expect sequence.
  213.  * Return 0 for matching string, 1 for timeout before we found it.
  214.  * FIXME:  we only time out if the other end stops sending.  If it
  215.  *       keeps sending, we keep listening forever.
  216.  */
  217. instr(s,n)
  218. register char *s;
  219. register int n;
  220. {
  221.     register int data;
  222.     register char    *pattern;
  223.     register int i;
  224.  
  225.     if (DEBUG_LEVEL(2)) {
  226.         printf("Expecting ");
  227.         for (i = 0; i < n; i++)
  228.             printf("%02x%c ",s[i] & 0xFF, isprint(s[i])? s[i]: ' ');
  229.         printf("\nR ");
  230.     }
  231.  
  232.     pattern = s;
  233.  
  234.     while ((long)(data = xgetc()) != (long)EOF) {
  235.         data &= 0x7F;            /* Ignore parity */
  236.  
  237.         if (DEBUG_LEVEL(2)) {
  238.             printf("%02x%c ", data, isprint(data)? data: ' ');
  239.         }
  240.  
  241.     tryfirst:
  242.  
  243.         if (data == *pattern) {
  244.             /* Input matches next byte of pattern */
  245.             pattern++;
  246.             if (pattern >= &s[n]) {
  247.                 if (DEBUG_LEVEL(2)) putchar('\n');
  248.                 return 0;        /* Done */
  249.             }
  250.         } else {
  251.             /* Input doesn't match pattern */
  252.             if (pattern == s) continue;    /* First char */
  253.             /* FIXME!  This doesn't work if pattern can match
  254.              * in more than one way initially, e.g.:
  255.              * "NECT" works when "CONNECT" is output, but
  256.              * "NNECT" fails when "CONNNECT" is output... */
  257.             pattern = s;    /* Does cur char match first? */
  258.             goto tryfirst;    /* FIXME */
  259.         }
  260.     }
  261.  
  262.     if (DEBUG_LEVEL(2))    putchar('\n');
  263.     DEBUG(1, "Didn't see expected string '%s'\n", s);
  264.     return 1;
  265. }
  266.  
  267. /*
  268.  * Debugging hack for stuff written to the modem.
  269.  */
  270. int
  271. twrite(s, n)
  272.     char *s;
  273.     int    n;
  274. {
  275.     register int i;
  276.  
  277.     if (DEBUG_LEVEL(2)) {
  278.         printf("Wrote:  ");
  279.         for (i = 0; i < n; i++)
  280.             printf("%02x%c ",s[i] & 0xFF, isprint(s[i])? s[i]: ' ');
  281.         printf("\n");
  282.     }
  283.  
  284.     return xwrite(0, s, n);
  285. }
  286.  
  287. /*
  288.  * MAIN ROUTINE.
  289.  *
  290.  * This is called at program startup.  It parses the arguments to the
  291.  * program (if any) and sets up to receive a call on the modem.
  292.  *
  293.  * If there are no arguments, we assume the caller is already on standard
  294.  * input, waiting to do uucp protocols (past the login prompt), and we
  295.  * just handle one caller.
  296.  *
  297.  * If there is an argument, it is the name of the tty device where we
  298.  * should listen for multiple callers and handle login and password.
  299.  */
  300. main(argc,argv)
  301. int argc;
  302. char *argv[];
  303. {
  304.     int    ontheline = 1;
  305.     int    i;
  306.     int c;
  307.     char tmp_str[255];
  308.     char    *poll_sys = (char *)NULL;  /* System name to poll, or none */
  309.     int c1, c2;
  310.     int retval;
  311.     SetApplLimit(GetApplLimit()-70000);
  312.     MaxApplZone();
  313.     MoreMasters();
  314.     MoreMasters();
  315.     srand(time(NULL));
  316. #ifdef MSDOS
  317.     fprintf(stderr, "\n\n");
  318.     fprintf(stderr, "UUCICO  : for MS-DOS             Ver 0787-2.05a\n");
  319.     fprintf(stderr, "Base code from gnuucp - hoptoad version 1.27\n");
  320.     fprintf(stderr, "Copyright 1987 Free Software Foundation, Inc.  Copying by GNU rules only,\n");
  321.     fprintf(stderr, "e.g. copies must include source code as well as binaries!\n");
  322.     fprintf(stderr, "Modified by Garry M. Paxinos\n");
  323.     fprintf(stderr, "FidoNet : 135/6   the 'Eye of Osiris'   SEAdog/OPUS/Dutchie/uuslave\n");
  324.     fprintf(stderr, "        : 135/17  Megasystems Online    OPUS/Dutchie\n");
  325.     fprintf(stderr, "UUCP    : ...!{allegra|codas|ucf-cs}!novavax!ankh!pax\n");
  326.     fprintf(stderr, "USNail  : % Megasystems Inc. 1075 Broken Sound Pkwy NW, Boca Raton FL 33431\n\n");
  327.  
  328. #endif
  329.     if (signal(SIGINT, sigint) == SIG_ERR) {
  330.         fprintf(stderr,"Couldn't set SIGINT\n");
  331.         abort();
  332.         }
  333.     _atexit(gnuucp_cleanup);
  334.     console_options.pause_atexit = true;
  335.     printf("\n");
  336.     SetWTitle((WindowPtr)(stdout->window), "\pMac/gnuucp");
  337.     argc = ccommand(&argv);
  338.     debug = -1;        /* Let read_params set it if -x doesn't */
  339.     ttynam[0] = '\0';
  340.     /* FIXME, use getopt */
  341.     /* scan command line arguments, kinda kludgy but it works */
  342.     for (i = 1; i < argc; i++) {
  343.         if (argv[i][0] != '-')
  344.             break;
  345.         switch (argv[i][1]) {
  346.  
  347.         case 'w':
  348.             f_wait++;
  349.             printf("uucico: will wait for call after outbound\n");
  350.             break;
  351.  
  352.         case 'x':
  353.             debug = atoi(&argv[i][2]);
  354.             break;
  355.  
  356.         case 'S':
  357.             ignore_time_restrictions++;
  358.         case 's':
  359.             poll_sys = &argv[i][2];
  360.             ontheline = 0;
  361.             break;
  362.  
  363.         case 'e':
  364.             loop++;
  365.             printf("uucico: endless loop mode\n");
  366.             break;
  367.  
  368.         case 'C':
  369.             uuControl = &argv[i][2];
  370.             break;
  371.  
  372.         /* Is -t needed for MSDOS?  Why?  -- hoptoad!gnu */
  373.         case 't':
  374.             curtemp++;
  375.             printf("uucico: using ~uutemp.$$$ for temp file\n");
  376.             break;
  377.         }
  378.     }
  379.  
  380.     /* If argument provided, use it as name of comm port */
  381.     if (i < argc) {
  382.         ontheline = 0;
  383.         strcpy(ttynam, argv[i]);
  384.     }
  385.     read_params(uuControl);        /* Read control file */
  386.     if (chdir(Spool)) {
  387.         perror("Can't chdir to Spool directory");
  388.         exit(EXIT_ERR);
  389.     }
  390.     /*
  391.      * If running via getty/login, our debug stdout had better
  392.      * go to a file, not to the usual stdout!
  393.      */
  394.     if (DEBUG_LEVEL(0) && ontheline) {
  395.         sprintf(tmp_str,"%s:%s", Spool, "gnuucp.log");
  396.         freopen(tmp_str, "a", stdout);
  397.     }
  398.  
  399.     /* setbuf(stdout, (char *)NULL);    Unbuffered debug output */
  400.  
  401.     /* If we are running with minimal debugging
  402.        then don't pause at program termination
  403.     */
  404.     if (debug == 0) console_options.pause_atexit = false;
  405.     
  406.     /* Timestamp the long debug log */
  407.     if (DEBUG_LEVEL(0)) {
  408.         printf("\n\n\n\ngnuucp log on tty '%s' starting %s\n",
  409.             ttynam, time_and_pid());
  410.     }
  411.  
  412.     /* Log our presence so we humans reading the logs can find the
  413.        entries created by gnuucp. */
  414.     logit("GNUUCP", version);
  415.     if (poll_sys) {
  416.         if (*poll_sys == '\0') poll_sys = (char *)NULL;
  417.         do_rmail_queue();
  418.         call_system(poll_sys);
  419.         uuxqt(debug);
  420.         if (!f_wait) goto end;
  421.     }
  422.  
  423.     do {
  424.         /*
  425.          *  Set up serial channel, wait for incoming call. 
  426.          */
  427.  
  428.         do_rmail_queue();
  429.         DEBUG(0, "\nRestarting\n", 0);
  430.         /* openline(ttynam, 0);  FIXME, let user specify baudrate */
  431.  
  432.         retval = do_session(ontheline, ttynam);
  433.  
  434.         uuxqt(debug);
  435.         DEBUG(0, "\nEnd of call\n", 0);
  436.  
  437.     } while (loop && !ontheline && (retval == EXIT_OK));
  438.  
  439. end:
  440.     return(0);
  441.     }
  442.  
  443. debuggit()
  444. {
  445. #ifdef UNIX
  446.     if (fork() == 0)
  447.         execlp("forktest", "testing file descriptors", 0);
  448. #endif
  449. }
  450.  
  451. /*
  452.  * Handle a single set of uucp expect/send strings.
  453.  *
  454.  * Return SUCCESS if the expect string is found, or FAIL if not.
  455.  */
  456. sendexpect(expect, send)
  457.     register char *expect;
  458.     char *send;
  459. {
  460.     char *dasher, *dancer;
  461.  
  462.     while ((dasher = strchr(expect, '-'))
  463.         && (dancer = strchr(dasher+1, '-'))) {
  464.         /* Two dashes found -- we have an expect-send-expect string */
  465.         *dasher = '\0'; *dancer = '\0';
  466.         if (instr(expect, dasher-expect) == 0)
  467.             goto sendit;
  468.         xlat_str(dasher+1);        /* Send the alternative */
  469.         expect = dancer + 1;        /* Try next pair, if any */
  470.     }
  471.         
  472.     if (expect[0] != '"' || expect[1] != '"' || expect[2] != '\0')
  473.         if (instr(expect, strlen(expect)))
  474.             return FAIL;
  475.  
  476. sendit:
  477.     if (send) {
  478.         xlat_str(send);
  479.     }
  480.     return SUCCESS;
  481. }
  482.  
  483.  
  484. /*
  485.  * translate embedded escape characters in a "send" string, and send 'em.
  486.  */
  487. xlat_str(msg)
  488.     register char    *msg;
  489. {
  490.     register int    i  = 0,
  491.         j  = 0;
  492.     int    cr = 1;
  493.     char    out[MAX_STRING+SLOP];
  494.  
  495.     gnusleep(1);        /* Old uucp did this, guess we'd better */
  496.     while (msg[i]) {
  497.         if (msg[i] == '\\') {
  498.             switch (msg[++i]) {
  499.             case 'r':            /* carriage return */
  500.                 out[j++] = 0x0d;
  501.                 break;
  502.             case 'n':            /* line feed */
  503.                 out[j++] = 0x0a;
  504.                 break;
  505.             case '\\':           /* back slash */
  506.                 out[j++] = '\\';
  507.                 break;
  508.             case 't':            /* tab */
  509.                 out[j++] = '\t';
  510.                 break;
  511.             case 'd':            /* delay */
  512.                 /* Print output, delay, resume */
  513.                 twrite(out, j);
  514.                 j = 0;
  515.                 if (DEBUG_LEVEL(2)) printf("(sleep)  ");
  516.                 gnusleep(1);
  517.                 break;
  518.             case 's':            /* space */
  519.                 out[j++] = ' ';
  520.                 break;
  521.             case 'c':            /* no CR at end */
  522.                 cr = 0;
  523.                 break;
  524.             default:            /* don't know so skip it */
  525.                 break;
  526.             }
  527.             i++;
  528.         } else {
  529.             out[j++] = msg[i++];
  530.         }
  531.     }
  532.  
  533.     if (cr)
  534.         out[j++] = 0x0d;
  535.  
  536.     if (j) twrite(out, j);
  537. }
  538.  
  539. /*
  540.  * Line finder.  Given an "ACU" specifier from the L.sys file,
  541.  * and a baud rate, determine a file name that we should try to lock
  542.  * and open.
  543.  *
  544.  * On initial call, pass in (struct port *)0 as the port argument.
  545.  * On subsequent calls, we skip past that port, which is presumed to
  546.  * have been tried and failed.
  547.  *
  548.  * If we find a matching entry in the config file ports database,
  549.  * return it; else return a dummy entry that might let the user get
  550.  * by with specifying just the device name for hardwired lines.
  551.  */
  552. #ifdef FIXME
  553. static struct port dummyport = {
  554.     "",                /* Name -- filled in later */
  555.     "none",                /* Modem type */
  556.     "",                /* Dev name -- filled in later */
  557.     0,                /* Baud rate -- filled in later */
  558.     (struct port *)0};        /* Chain */
  559. #endif FIXME
  560.  
  561. struct port *
  562. findport(name, p)
  563.     char    *name;
  564.     struct port *p;
  565. {
  566.  
  567.     if (p == 0)
  568.         p = ports;
  569.     else
  570.         p = p->chain;
  571.  
  572.     for ( ; p; p = p->chain) {
  573.         if (strcmp(name, p->devname) == 0)
  574.             return p;
  575.     }
  576.  
  577.     return p;            /* Didn't find it -- return null ptr */
  578. }
  579.     
  580. struct port *
  581. pickport(acu, baud, p)
  582.     char    *acu;
  583.     long    baud;
  584.     struct port *p;
  585. {
  586.  
  587.     if (p == 0)
  588.         p = ports;
  589.     else
  590.         p = p->chain;
  591.  
  592.     for ( ; p; p = p->chain) {
  593.         if (baud == p->baud &&
  594.             strcmp(acu, p->portname) == 0)
  595.             return p;
  596.     }
  597.  
  598.     return p;            /* Didn't find it -- return null ptr */
  599.  
  600. #ifdef FIXME
  601.     strcpy(dummyport.portname, acu);    /* Fill in acu name */
  602.     strcpy(dummyport.devname,  acu);    /* Fill in acu name */
  603.     dummyport.baud = baud;
  604.     return &dummyport;
  605. #endif FIXME
  606. }
  607.  
  608.  
  609. /*
  610.  * Simple dialer routine.  Needs replacement with a full blown
  611.  * script driven dialer.  Next week maybe :-).  FIXME.
  612.  */
  613. dial_nbr(port, nbr)
  614.     struct port *port;
  615.     char  *nbr;
  616. {
  617.     char  dial[30];
  618.     char  conn[30];
  619.     SerStaRec serSta;
  620.     int   i;
  621.  
  622.     /* Hardwired lines do no dialing. */
  623.     if (strcmp("none", port->modemname) == 0)
  624.         return SUCCESS;
  625.  
  626.     /* If it doesn't say hayes, we can't dial it. */
  627.     if (strcmp("hayes", port->modemname) != 0)
  628.         return FAIL;
  629.  
  630.     sprintf(dial, "ATV1DT %s\r", nbr);
  631.     
  632.     if (DEBUG_LEVEL(2))
  633.         printf("dialing %s at %ld baud: %s\n",
  634.             port->devname, port->baud, dial);
  635.     /* SerStatus(inRefNum, &serSta); */
  636.     twrite(dial, strlen(dial));
  637.     gnusleep(ConnectWait);
  638.     /* while (!serSta.ctsHold)
  639.             {
  640.                 HandleEvents();
  641.                 SerStatus(inRefNum, &serSta);
  642.                 } */
  643. /* FIXME, we've got to be more flexible here... */
  644. /* sprintf(conn, "CONNECT %s\r", baud);*/
  645.     sprintf(conn, "CONNECT");
  646.  
  647.  
  648.     i = instr(conn, strlen(conn));
  649.  
  650.     /* FIXME, scan out the baud rate, or whatever's before the CR, here.
  651.      */
  652.  
  653.     if (!i) gnusleep(2);    /* Let the line settle. */
  654.  
  655.     return (i);
  656. }
  657.  
  658. /*
  659.  * Call a specific system, or all systems that have work pending.
  660.  */
  661. call_system(sys)
  662.     char    *sys;
  663. {
  664.     FILE    *lsys;
  665.     char    buf[MAX_LSYS];
  666.     char     tmp_str[255];
  667.     char    sysnam[MAX_HOST];
  668.     char    prev_name[MAX_HOST];
  669.     int    called = FAIL;
  670.  
  671.     /*
  672.      * Unix uucico just reads the directory, and calls the systems
  673.      * in the order of the files in the directory.  We want more
  674.      * control than that, though I'm not sure that L.sys order is
  675.      * best either.  For example, in the first call after 11PM,
  676.      * I'd like to call the sites that haven't been callable before
  677.      * 11PM first, and finish up with the ones I've been able to call
  678.      * all day.  FIXME.
  679.      */
  680.     /* sprintf(tmp_str,"%s:%s", Spool, "L.sys"); */
  681.     if (! (lsys =fopen(Sysfile, "r"))) {
  682.         DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
  683.         return 0;
  684.     }
  685.     sysnam[0] = '\0';        /* Initially, no previous sys */
  686.  
  687.     /* Once per system in L.sys... */
  688.     /* FIXME, handle continuation lines (trailing "\") */
  689.     while (fgets(buf, sizeof buf, lsys)) {
  690.         if (buf[strlen(buf)-1] = '\n')
  691.             {
  692.                 buf[strlen(buf)-1] = '\0';
  693.                 }
  694.         if (buf[0] == '#')
  695.             continue;
  696.         
  697.         /*
  698.          * Grab the system name.  If same as previous, and
  699.          * the previous call worked, skip it.
  700.          */
  701.         strcpy(prev_name, sysnam);
  702.         (void) sscanf((char *)buf, "%s", sysnam);
  703.         if (!strcmp(sysnam, prev_name)) {
  704.             if (called == SUCCESS) continue;
  705.         }
  706.  
  707.         /*
  708.          * If a system name was specified, skip til we find it
  709.          * If none was specified, only call if there is work.
  710.          */
  711.         if (sys) {
  712.             if (0 != strcmp(sys, sysnam))
  713.                 continue;
  714.         } else {
  715.             DEBUG(4,"searching for outbound to %s\n", sysnam);
  716.  
  717.             if (!work_scan(sysnam, "C")) {
  718.                 DEBUG(3,"no work for %s\n", sysnam);
  719.                 called = SUCCESS;    /* Don't try further */
  720.                 continue;
  721.             }
  722.  
  723.             DEBUG(3, "found work for %s\n", sysnam);
  724.         }
  725.  
  726.         called = call_sysline(buf);
  727.  
  728.         if (called == SUCCESS && sys) break;
  729.     }
  730.  
  731.     fclose(lsys);
  732.     if (called == FAIL && sys)
  733.         DEBUG(0, "Could not call system %s\n", sys);
  734.     return 0;
  735. }
  736.  
  737. /*
  738.  * Call out to a system, given its L.sys line.
  739.  */
  740. int
  741. call_sysline(lsysline)
  742.     char    *lsysline;
  743. {
  744.     char    tempname[MAX_HOST + 30 + SLOP],
  745.         *sysnam,
  746.         *times,
  747.         *acu,
  748.         *sbaud,
  749.         *telno,
  750.         *send,
  751.         *expect;
  752.     struct port *port;
  753.     char    logbuf[MAX_HOST+30+SLOP];
  754.     char    msgbuf[MAX_STRING+SLOP];
  755.     int    baud;
  756.  
  757.     who[0] = '-'; who[1] = '\0';    /* No user now (for logit) */
  758.  
  759.     /* FIXME, use the values it is ignoring here */
  760.     sysnam = strtok(lsysline, " ");
  761.     times = strtok((char *)NULL, " ");    /* Time */
  762.     acu = strtok((char *)NULL, " ");    /* ACU */
  763.     sbaud = strtok((char *)NULL, " ");    /* Baud */
  764.     telno = strtok((char *)NULL," ");    /* phone */
  765.  
  766.     strcpy(host_name, sysnam);
  767.  
  768.     if (!ignore_time_restrictions) {
  769.         /* FIXME, check the time parameter and return FAIL if
  770.          * it does not allow calls now.  Meanwhile, bounce
  771.          * all calls unless -S is specified. */
  772.         logit("WRONG TIME TO CALL", sysnam);
  773.         return FAIL;
  774.     }
  775.  
  776.     baud = atoi(sbaud);
  777.  
  778.     port = (struct port *)0;
  779.     for (;;) {
  780.         port = pickport(acu, baud, port);
  781.         if (!port)
  782.             return FAIL;        /* Tried them all */
  783.         DEBUG(2, "Opening outgoing line %s\n", port->devname);
  784.         if (openout(port) != SUCCESS) {
  785.             logit("CAN'T USE", port->devname);
  786.         } else {
  787.             break;
  788.         }
  789.     }
  790.  
  791.     sprintf(logbuf, "%s %s %d", host_name, port->devname, port->baud);
  792.     DEBUG(1, "Trying %s\n", logbuf);
  793.  
  794.     if (dial_nbr(port, telno)) {
  795.         ttyunlock();
  796.         logit("FAILED", logbuf);
  797.         return FAIL;
  798.     }
  799.  
  800.     logit("DIALED", logbuf);
  801.  
  802.     /*
  803.      * Process send-expect strings.
  804.      */
  805.     while (expect = strtok((char *)NULL, " ")) {
  806.         send = strtok((char *)NULL, " ");
  807.         if (sendexpect(expect, send) != SUCCESS)
  808.             goto bort1;
  809.     }
  810.  
  811.     /*
  812.      * FIXME, there should be a way to detect login/passwd
  813.      * failure here and keep doing the script rather than
  814.      * continuing to expect Shere at another login: prompt.
  815.      */
  816.     sprintf(logbuf, "call to %s", host_name);
  817.     logit("SUCCEEDED", logbuf);
  818.  
  819.     /* wait for Shere message, grab whatever is sent, send response */
  820.     sprintf(tempname, "\20Shere");
  821.     if (instr(tempname, strlen(tempname)))
  822.         goto bort1;
  823.     if (getstring(msgbuf) != SUCCESS)
  824.         goto bort1;
  825.     if (msgbuf[0] == '=') {
  826.         if (!!strcmp(host_name, msgbuf+1)) {
  827.             logit("WRONG HOST", msgbuf);
  828.             goto bort1;
  829.         }
  830.     } else if (msgbuf[0] != '\0') {
  831.         DEBUG(0, "strange Shere%s\n", msgbuf);
  832.     }
  833.  
  834.     sprintf(tempname, "\20S%s\0", Myname);
  835.     twrite(tempname, strlen(tempname)+1); /* Including null */
  836.  
  837.     /* wait for ok message */
  838.     if (getstring(msgbuf) != SUCCESS)
  839.         goto bort1;
  840.     if (msgbuf[0] != 'R')
  841.         goto bort1;
  842.     if (strcmp("OK", msgbuf+1)) {
  843.         logit("HANDSHAKE FAILED", msgbuf+1);
  844.         goto bort1;
  845.     }
  846.  
  847.     /*
  848.      * Get Protocol string, make sure it supports our protocol.
  849.      * FIXME, should scan our table versus theirs.
  850.      */
  851.     if (getstring(msgbuf) != SUCCESS)
  852.         goto bort1;
  853.     if (msgbuf[0] != 'P')
  854.         goto bort1;
  855.     if (!strchr(msgbuf+1, curproto->p_id)) {
  856.         logit("PROTOCOL UNSUPPORTED", msgbuf);
  857.         goto bort1;
  858.     }
  859.     twrite(msgi3, sizeof(msgi3)-1);    /* FIXME, build real reply */
  860.  
  861.     if (turnon(1))
  862.         goto bort1;
  863.  
  864.     logit("OK", "startup");
  865.  
  866.     top_level(1);
  867.     hangup(port);
  868.     return SUCCESS;
  869.  
  870. bort1:
  871.     hangup(port);
  872.     return FAIL;
  873. }
  874.  
  875. /* Handle a single uucp [slave] login session */
  876. do_session(ontheline, ttynam)
  877.     int ontheline;
  878.     char *ttynam;
  879.     {
  880.     char    trash[MAX_STRING+SLOP];    /* Incoming trash buffer */
  881.     char tmp_str[255];
  882.     char ch;
  883.     SerStaRec serSta;
  884.     struct port *p;
  885.     if (!ontheline) {
  886.         p = (struct port *)0;
  887.         serSta.ctsHold = 0;
  888.         p = findport(ttynam, p);
  889.         if (p == (struct port *)NULL)
  890.             {
  891.                 logit("Can't find port to", "open");
  892.                 return(EXIT_ERR);
  893.                 }
  894.         openin(p);
  895.         /* Look for signs of life on line */
  896.         while (instr("CONNECT",7));
  897.         twrite(msgo0,sizeof(msgo0)-1);
  898.         sprintf(tmp_str, "%s\r", UUCPlogname);
  899.         if (instr(tmp_str,strlen(tmp_str))) {
  900.             printf("uucico: invalid login name\n");
  901.             goto bort;
  902.         }
  903.  
  904.         /* output password request, verify password */
  905.         twrite(msgo1,sizeof(msgo1)-1);
  906.         sprintf(tmp_str, "%s\r", UUCPpasswd);
  907.         if (instr(tmp_str,strlen(tmp_str))) {
  908.             printf("uucico: invalid password\n");
  909.             goto bort;
  910.         }
  911.  
  912.         printf("uucico: correct login\n");
  913.     }
  914.  
  915.     /* output here message, wait for response */
  916.     twrite(msgo2,sizeof(msgo2)-1);
  917. /* FIXME, handle this kludge */
  918. /*    if (instr(msgi2,sizeof(msgi2)-1)) */
  919.     if (getstring(trash) != SUCCESS || trash[0] != 'S')
  920.         goto bort;
  921.  
  922.     strcpy (host_name, strtok(trash, "\20S "));
  923.  
  924.     /* output ROK message, output protocol request, wait for response */
  925.     twrite(msgo3,sizeof(msgo3)-1);
  926.  
  927.     /* FIXME, make the protocol list here, and use it */
  928.     twrite(msgo3a,sizeof(msgo3a)-1);
  929.     if (instr(msgi3,sizeof(msgi3)-1))
  930.         goto bort;
  931.  
  932.     if (turnon(0)) goto bort;
  933.     logit("OK", "startup");
  934.     top_level(0);        /* Returns SUCCESS or FAIL, we dont care */
  935.  
  936. bort:
  937.     hangup(p);
  938.     printf("uucico: call complete\n");
  939.     return(EXIT_OK);
  940. }
  941.  
  942. /*
  943.  * Handle transactions "at top level", as Unix uucp's debug log says.
  944.  *
  945.  * As master, we scan our queues for work and send requests to the
  946.  * other side.  When done, we send a hangup request and switch to slave mode.
  947.  *
  948.  * As slave, we accept requests from the other side; when it is done,
  949.  * it sends a hangup request, and we switch to master mode, if we have
  950.  * any work queued up for that system.
  951.  *
  952.  * This repeats as long as either side has work to do.  When all the
  953.  * queued work is done, we agree to hang up, terminate the packet protocol,
  954.  * and return to the caller.  (We still haven't hung up the phone line yet.)
  955.  *
  956.  * A curious feature of the hangup protocol is that it is not a simple
  957.  * question-answer.  The master says "H", asking about hangup.  The
  958.  * slave responds "HY" saying OK.  The master then says "HY" also,
  959.  * then both of them hang up.  Maybe this is to make sure the first HY
  960.  * got ack'ed?  Anyway, an "H" is reported as HANGUP and an "HY" as
  961.  * HANGNOW.  After we send an HY, we go back to listening for commands;
  962.  * if the master sends something other than HY, we'll do it.
  963.  */
  964. #define    HANGUP    2        /* Signal to switch master/slave roles */
  965. #define    HANGNOW    3        /* Signal to hang up now */
  966. #define    COPYFAIL    4    /* File copy failed */
  967.  
  968. int
  969. top_level(master_mode)
  970.     int master_mode;
  971. {
  972.     char    buf[MAXMSGLEN];        /* For hangup responses */
  973.  
  974.     if (master_mode) {
  975.         (void) work_scan(host_name, "C"); /* Kick off queue scan */
  976.         goto master;
  977.     }
  978.  
  979.     for (;;) {
  980.         /* Slave side */
  981.     slave:
  982.         for (;;) {
  983.             DEBUG(4, "*** TOP *** - slave\n", 0);
  984.             switch (do_one_slave()) {
  985.             case SUCCESS:
  986.                 break;
  987.             case FAIL:
  988.                 return FAIL;
  989.             case HANGUP:
  990.                 if (work_scan(host_name, "C")) {
  991.                     if (wrmsg('H', "N", fdtty))
  992.                         return FAIL;
  993.                     goto master;
  994.                 } else {
  995.                     if (wrmsg('H', "Y", fdtty))
  996.                         return FAIL;
  997.                     break;
  998.                 }
  999.             case HANGNOW:
  1000.                 goto quit;
  1001.             }
  1002.         }
  1003.     
  1004.         /* Master side */
  1005.     master:
  1006.         for (;;) {
  1007.             DEBUG(4, "*** TOP *** - master\n", 0);
  1008.             switch (do_one_master()) {
  1009.             case SUCCESS:
  1010.                 break;
  1011.             case FAIL:
  1012.                 return FAIL;
  1013.             case HANGUP:
  1014.                 /* We wrote an H command, what's the resp? */
  1015.                 if ((long)rdmsg(buf, fdtty) != (long)SUCCESS)
  1016.                     return FAIL;
  1017.                 if (buf[0] != 'H')
  1018.                     return FAIL;
  1019.                 if (buf[1] == 'N')
  1020.                     goto slave;
  1021.                 else {
  1022.                     /* Write the final HY */
  1023.                     if (wrmsg('H', "Y", fdtty))
  1024.                         return FAIL;
  1025.                     goto quit;
  1026.                 }
  1027.             }
  1028.         }
  1029.     }
  1030.  
  1031. quit:
  1032.     /* Shut down the packet protocol */
  1033.     turnoff();
  1034.  
  1035.     /* Write the closing sequence */
  1036.     twrite(msgo4, sizeof(msgo4)-1);
  1037.     (void) instr(msgi4, sizeof(msgi4)-1);
  1038.  
  1039.     twrite(msgo4, sizeof(msgo4)-1);
  1040.  
  1041.     logit("OK", "conversation complete");
  1042.  
  1043.     return SUCCESS;   /* Go byebye */
  1044. }
  1045.  
  1046. /*
  1047.  * We are slave; get a command from the other side and execute it.
  1048.  *
  1049.  * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
  1050.  */
  1051. int
  1052. do_one_slave()
  1053. {
  1054.     char msg[MAXMSGLEN];        /* Master's message to us */
  1055.  
  1056.     /* Get master's command */
  1057.     if ((long)rdmsg(msg, fdtty) != (long)SUCCESS)
  1058.         return FAIL;
  1059.  
  1060.     /* Print it for easy debugging */
  1061.     DEBUG(4,"Command: %s\n\n", msg);
  1062.  
  1063.     switch (msg[0]) {
  1064.  
  1065.     case 'S':
  1066.         if (msg[1] != ' ') break;
  1067.         return host_send_file(msg);
  1068.  
  1069.     case 'R':
  1070.         if (msg[1] != ' ') break;
  1071.         return host_receive_file(msg);
  1072.  
  1073.     case 'X':
  1074.         /* Cause uuxqt to run (on certain files?)
  1075.          * See Protocol.doc for sketchy details.
  1076.          */
  1077.         break;
  1078.  
  1079.     case 'H':
  1080.         if (msg[1] == '\0') return HANGUP;
  1081.         if (msg[1] == 'Y')  return HANGNOW;
  1082.         if (msg[1] == 'N')  return SUCCESS;    /* Ignore HN to slave */
  1083.         break;
  1084.  
  1085.     }
  1086.  
  1087.     /* Unrecognized packet from the other end */
  1088.     DEBUG(0, "Bad control packet refused: %s\n", msg);
  1089.     if (yesno(msg[0], 0, 0))    /* FIXME: return error code */
  1090.         return FAIL;
  1091.     return SUCCESS;
  1092. }
  1093.  
  1094. /*
  1095.  * Do one piece of work as master.
  1096.  *
  1097.  * FIXME:  we don't handle the flags, e.g. -c, properly!
  1098.  */
  1099. int
  1100. do_one_master()
  1101. {
  1102.     FILE    *fd;
  1103.     char    *sname;
  1104.     char    cmnd[1];        /* Command character */
  1105.     char     buf[100];
  1106.     char    tmp_str[255];
  1107.     int    fail;
  1108.     int    num;
  1109.     char    notify[NAMESIZE];    /* A bit large...FIXME */
  1110.             /* FIXME: do the notify stuff */
  1111.  
  1112.     sname = work_next();
  1113.     if (!sname) {
  1114.         /* No more work, time to hang up. */
  1115.         if (wrmsg('H', "", fdtty))
  1116.             return FAIL;
  1117.         return HANGUP;
  1118.     }
  1119.  
  1120.     DEBUG(4, "Request file %s\n", sname);
  1121.     sprintf(tmp_str,"%s:%s", Spool, munge_filename(sname));
  1122.     fd = fopen(tmp_str, "rb");
  1123.     if (fd == NULL) {
  1124.         DEBUG(0, "uucico: couldn't open %s\n", sname);
  1125.         /* fail = local_receive_file(buf); */
  1126.         fail = local_receive_file();
  1127.         return SUCCESS;
  1128.     }
  1129.     setvbuf(fd, NULL, _IOFBF, 4096);
  1130.     while (fgets(buf, sizeof buf, fd)) {
  1131.         DEBUG(4, "Queued request: %s", buf);
  1132.         if (buf[1] != ' ') goto badnum;
  1133.         num = sscanf((char *)buf, "%s %s %s %s %s %s %o\n",
  1134.             cmnd, srcnam, dstnam, who, flags, temp, &mode, notify);
  1135.  
  1136.         switch (cmnd[0]) {
  1137.         case 'S':
  1138.             if (num < 7 || num > 8) goto badnum;
  1139.             fail = local_send_file(buf);
  1140.             break;
  1141.  
  1142.         case 'R':
  1143.             if (num != 5) goto badnum;
  1144.             break;
  1145.  
  1146.         default: badnum:
  1147.             DEBUG(0, "Unknown/invalid queued request: %s\n",
  1148.                  buf);
  1149.             goto badline;
  1150.         }
  1151.  
  1152.         /* FIXME, what does uucp do if one of N xfers fails? */
  1153.         if (fail == FAIL) {
  1154.             /* protocol over the wire is failing */
  1155.             fclose(fd);
  1156.             return FAIL;
  1157.         }
  1158.         if (fail) {
  1159.     badline:
  1160.             logit("ERROR IN WORK FILE", sname);
  1161.             logit("BAD LINE IS", buf);
  1162.         }
  1163.     }
  1164.     fclose(fd);
  1165.  
  1166.     /* Zap the queue file */
  1167.     sprintf(tmp_str,"%s:%s", Spool, munge_filename(sname));
  1168.     fail = remove(tmp_str);
  1169.     if (fail != 0) {
  1170.         logit("CAN'T REMOVE WORK FILE", sname);
  1171.         DEBUG(0, "Can't remove, errno %d\n", errno);
  1172.     } else {
  1173.         DEBUG(4, "Removed work file %s\n", sname);
  1174.     }
  1175.     return SUCCESS;
  1176. }
  1177.  
  1178. /* Send a "yes or no" packet with character 'c'. */
  1179. int
  1180. yesno(c, true, err)
  1181.     char c;
  1182.     int true;
  1183.     int err;
  1184. {
  1185.     char buf[20];
  1186.  
  1187.     buf[0] = true? 'Y': 'N';
  1188.     buf[1] = 0;
  1189.     if (err && !true) 
  1190.         sprintf(buf+1,"%d", err);
  1191.  
  1192.     return wrmsg(c, buf, fdtty);
  1193. }
  1194.  
  1195. /*
  1196.  * Master wishes to send a file to us -- we receive it.
  1197.  * Return 1 to abort the call, 0 to continue.
  1198.  */
  1199. int
  1200. host_send_file(msg)
  1201. char  *msg;
  1202. {
  1203.     FILE *fddsk;            /* Disk file pointer */
  1204.     char tmp_str[255];
  1205.     char    cmnd[1];        /* Command character */
  1206.  
  1207.     sscanf((char *)msg,"%s %s %s %s %s %s %o",
  1208.         cmnd, srcnam, dstnam, who, flags, temp, &mode);
  1209.     logit("REQUESTED", msg);
  1210.     strcpy (dstnam, munge_filename(dstnam));  /* Translate to local name */
  1211.     strcpy (temp, temp_filename(dstnam));     /* Create a handy temp file */
  1212.  
  1213.     /* FIXME: deal with file modes now that we fopen. */
  1214.     sprintf(tmp_str, "%s:%s", Spool, temp);
  1215.     fddsk = fopen(tmp_str, "wb" /*, mode|0600 */);
  1216.     if (fddsk == NULL) {
  1217.         /* Can't open file -- send error response */
  1218.         if (DEBUG_LEVEL(0)) {
  1219.             printf(
  1220.             "Cannot open temp file %s (%s) for writing, errno=%d\n",
  1221.                 temp, dstnam, errno);
  1222.         }
  1223.         logit("REQUEST", "FAILED -- TEMP FILE");
  1224.         if (yesno('S', 0, 4))
  1225.             return FAIL;
  1226.         return SUCCESS;
  1227.     }
  1228.     setvbuf(fddsk, NULL, _IOFBF, 4096);
  1229.     
  1230.     /* FIXME: Are the above permissions right?? */
  1231.     /* FIXME: Should we create directories for the file? */
  1232.     if (yesno('S',1, 0))    /* Say yes */
  1233.         return 1;
  1234.  
  1235.     return receive_file(fddsk, temp, dstnam, srcnam);
  1236. }
  1237.  
  1238. /*
  1239.  * Master wants to Recieve a file from us -- we send it.
  1240.  * Return 1 to abort the call, 0 to continue.
  1241.  */
  1242. host_receive_file(msg)
  1243. char  *msg;
  1244. {
  1245.     FILE *fddsk;     /* Disk file descriptor */
  1246.     char tmp_str[255];
  1247.     int x;
  1248.     char    cmnd[1];        /* Command character */
  1249.  
  1250.     logit("REQUESTED", msg);
  1251.  
  1252.     sscanf((char *)msg,"%s %s %s",cmnd,srcnam,dstnam);
  1253.     strcpy (temp, munge_filename(srcnam));
  1254.     sprintf(tmp_str, "%s:%s", Spool, temp);
  1255.     fddsk = fopen(tmp_str, "rb");        /* Try to open the file */
  1256.     if (fddsk == NULL) {
  1257.         /* File didn't open, sigh. */
  1258.         if (DEBUG_LEVEL(0)) {
  1259.             printf("Cannot open file %s (%s) for reading, errno=%d\n",
  1260.                 temp, srcnam, errno);
  1261.         }
  1262.         logit("DENIED", "CAN'T OPEN");
  1263.         if (yesno('R', 0, 2))
  1264.             return 1;
  1265.         return 0;
  1266.     }
  1267.     setvbuf(fddsk, NULL, _IOFBF, 4096);
  1268.     
  1269.  
  1270.     if (yesno('R',1, 0))    /* Say yes */
  1271.         return 1;
  1272.  
  1273.     x = send_file(fddsk);
  1274.     switch (x) {
  1275.     default:
  1276.         return x;
  1277.  
  1278.     case COPYFAIL:
  1279.         /* We don't care if the copy failed, since the master
  1280.            asked for the file and knows the result. */
  1281.         return SUCCESS;
  1282.     }
  1283. }
  1284.  
  1285. /*
  1286.  * We, as master, want to Send a file.
  1287.  *
  1288.  * Return FAIL, SUCCESS, or COPYFAIL.
  1289.  * SUCCESS is returned either if the file was not found locally (local
  1290.  * error, and the queued transfer should be flushed) or if it was moved
  1291.  * successfully.  COPYFAIL indicates that the queued transfer should be
  1292.  * left queued, and later retried.  FIXME, there are several failure points
  1293.  * in the transaction (see Protocol.doc) and we need finer control here.
  1294.  */
  1295. int
  1296. local_send_file(workstr)
  1297.     char *workstr;
  1298. {
  1299.     char buf[MAXMSGLEN];    /* Used for both xmit and receive */
  1300.     FILE *fddsk;     /* Disk file descriptor */
  1301.     char tmp_str[255];
  1302.     int res, status;    /* Result and file removal status */
  1303.  
  1304.     /* WHY are temp and srcnam switched?  FIXME!  And no notify? */
  1305.     sprintf(buf,"S %s %s %s %s %s 0%o %s",
  1306.         temp, dstnam, who, flags, srcnam, mode, who);
  1307.  
  1308.     logit("REQUEST", buf);
  1309.  
  1310.     if (strchr(flags, 'c')) {
  1311.         strcpy(temp, munge_filename(srcnam));
  1312.     } else {
  1313.         strcpy(temp, munge_filename(temp));
  1314.     }
  1315.     sprintf(tmp_str, "%s:%s", Spool, temp);
  1316.     fddsk = fopen(tmp_str, "rb");
  1317.     if (fddsk == NULL) {
  1318.         /* FIXME -- handle queued request for nonexistent file */
  1319.         if (DEBUG_LEVEL(0))
  1320.             printf("Can't open file %s (%s), errno=%d\n",
  1321.                 temp, srcnam, errno);
  1322.         logit("NOT FOUND", temp);
  1323.         return COPYFAIL;    /* FIXME caller won't deal with this */
  1324.     }
  1325.     setvbuf(fddsk, NULL, _IOFBF, 4096);
  1326.     
  1327.     /* Tell the other side we want to send this file */
  1328.     if (wrmsg('S', buf+1, fdtty) != SUCCESS) {
  1329.         DEBUG(0, "problem sending request\n", 0);
  1330.         return FAIL;
  1331.     }
  1332.  
  1333.     /* See what they have to say about it */
  1334.     if ((long)rdmsg(buf, fdtty) != (long)SUCCESS)    
  1335.         return FAIL;
  1336.     if ((buf[0] != 'S') || (buf[1] != 'Y')) {
  1337.         logit("REQUEST DENIED", buf);
  1338.         return COPYFAIL;
  1339.     }
  1340.     res = send_file(fddsk);    /* FAIL, SUCCESS, or COPYFAIL */
  1341.  
  1342.     /* Delete the source file if it was just a copy */
  1343.     if (res != SUCCESS)
  1344.         return res;
  1345.     if (strchr(flags, 'c'))        /* If copied direct from source */
  1346.         return res;        /* ...just return. */
  1347.     status = remove(tmp_str);        /* Delete uucp's copy of the file */
  1348.     if (status != 0) {
  1349.         logit("CAN'T REMOVE SENT FILE", temp);
  1350.         DEBUG(0, "Can't remove, errno %d\n", errno);
  1351.     } else {
  1352.         DEBUG(4, "Removed sent file %s\n", temp);
  1353.     }
  1354.     return res;
  1355. }
  1356.  
  1357. /*
  1358.  * We want to Receive a file -- so we ask for it.
  1359.  * Return 1 to abort the call, 0 to continue.
  1360.  */
  1361. int
  1362. local_receive_file()
  1363. {
  1364.     char buf[MAXMSGLEN];
  1365.     FILE *fddsk;            /* Disk file pointer */
  1366.     char tmp_str[255];
  1367.  
  1368.     /* FIXME, test dest file access before we ask for it. */
  1369.  
  1370.     sprintf(buf,"R %s %s %s %s %s 0%o %s",
  1371.         srcnam, dstnam, who, flags, temp, mode, who);
  1372.  
  1373.     strcpy (dstnam, munge_filename(dstnam));  /* Translate to local name */
  1374.     strcpy (temp, temp_filename(dstnam));     /* Create a handy temp file */
  1375.  
  1376.     /* FIXME: deal with file modes now that we fopen. */
  1377.     /* FIXME: Are the above permissions right?? */
  1378.     /* FIXME: Should we create directories for the file? */
  1379.     sprintf(tmp_str, "%s:%s", Spool, temp);
  1380.     fddsk = fopen(tmp_str, "wb" /*, mode|060 */);
  1381.  
  1382.     if (fddsk == NULL) {
  1383.         /* Can't open temp file -- send error response */
  1384.         if (DEBUG_LEVEL(0)) {
  1385.             printf(
  1386.             "Cannot open temp file %s (%s) for writing, errno=%d\n",
  1387.                 temp, dstnam, errno);
  1388.         }
  1389.         logit("REQUEST", "FAILED -- TEMPFILE");
  1390.         return FAIL;
  1391.     }
  1392.     setvbuf(fddsk, NULL, _IOFBF, 4096);
  1393.     
  1394.     logit("REQUEST", buf);
  1395.     if (wrmsg('R', buf+1, fdtty) != SUCCESS) {
  1396.         printf("uucico: problem sending request\n");
  1397.         return FAIL;
  1398.     }
  1399.  
  1400.     /* See what the other side has to say about it */
  1401.     if ((long)rdmsg(buf, fdtty) != (long)SUCCESS)
  1402.         return FAIL;
  1403.     if ((buf[0] != 'R') || (buf[1] != 'Y')) {
  1404.         logit("REQUEST DENIED", buf);
  1405.         return SUCCESS;    /* FIXME, should do something more here */
  1406.     }
  1407.  
  1408.     return receive_file(fddsk, temp, dstnam, srcnam);
  1409.     /* FIXME - We should deal with files that didn't get there */
  1410. }
  1411.  
  1412. /* general file receive routine */
  1413. int
  1414. receive_file(fddsk, temp, dstnam, srcnam)
  1415.     FILE *fddsk;            /* Disk file pointer */
  1416.     char    *temp, *dstnam, *srcnam;
  1417. {
  1418.     int status;
  1419.     char tmp_str1[255];
  1420.     char tmp_str2[255];
  1421.     int error = 0;            /* No errors so far */
  1422.  
  1423.     if (rddata(fdtty, fddsk) != SUCCESS) error++;
  1424.     status = fclose(fddsk);        /* Make sure the data got here */
  1425.     if (status != 0) {
  1426.         error++;
  1427.         DEBUG(0, "fclose errno=%d\n", errno);
  1428.     }
  1429.  
  1430.     /* Move the file from its temp location to its real loc */
  1431.     /* FIXME:  This needs to be able to copy the file, if 
  1432.        a simple rename does not suffice. */
  1433.     /* FIXME:  should create directories if necessary, e.g. D.
  1434.        or subdirs of /usr/spool/uucppublic. */
  1435.     /* FIXME:  should use source name if target is a directory e.g. ~/ */
  1436.     sprintf(tmp_str1, "%s:%s", Spool, temp);
  1437.     sprintf(tmp_str2, "%s:%s", Spool, dstnam);
  1438.     status = rename(tmp_str1, tmp_str2);
  1439.     if (status != 0) {
  1440.         error++;
  1441.         if (DEBUG_LEVEL(0)) {
  1442.             printf("Cannot rename file %s to %s, errno=%d\n",
  1443.                 temp, dstnam, errno);
  1444.         }
  1445.     }
  1446.  
  1447.     logit("COPY", error? "FAILED": "SUCCEEDED");
  1448.     if (yesno('C', error == 0, 5))    /* Send yes or no */
  1449.         return FAIL;
  1450.     return SUCCESS;
  1451. }
  1452.  
  1453. /*
  1454.  * general file send routine
  1455.  * Return SUCCESS, FAIL, or COPYFAIL.
  1456.  */
  1457. int
  1458. send_file(fddsk)
  1459.     FILE *fddsk;     /* Disk file pointer */
  1460. {
  1461.     char ansbuf[MAXMSGLEN];
  1462.  
  1463.     if (wrdata(fddsk, fdtty) != SUCCESS)
  1464.         return FAIL;
  1465.     (void) fclose(fddsk);
  1466.     /* Await the "CY" or "CNddd" packet, and toss it. */
  1467.     while (1) {
  1468.         if ((long)rdmsg(ansbuf, fdtty) != (long)SUCCESS)    
  1469.             return FAIL;
  1470.         if (ansbuf[0] != 'C') {
  1471.             DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n",
  1472.                 ansbuf);
  1473.             /* and loop looking for C message */
  1474.         } else if (ansbuf[1] == 'Y') {
  1475.             logit("REQUESTED", ansbuf);
  1476.             return SUCCESS;
  1477.         } else {
  1478.             logit("COPY FAILED", ansbuf);
  1479.             return COPYFAIL;
  1480.         }
  1481.     }
  1482. }
  1483.  
  1484.